package java_thinking.unit_15._15_12;

/**
 * @Description :   古怪的循环泛型
 *
 *                  这里有些东西很重要：新类Subtype接受的参数和返回的值具有Subtype类型二不仅是
 *                  基类BasicHolder类型。这就是CRG本质：基类用导出类代替其参数，这意味着泛型基
 *                  类变成了一种其所有导出类的公共功能的模板，但是这些功能对于其所有参数和返回值，
 *                  将使用导出类型，也就是说，在所产生的类中将使用确切的类型而不是基类型，因此
 *                  在Subtype中，传递给set()的参数和从get()返回的类型都是确切的Subtype。
 *
 *                  用案例来分析
 *                  public abstract class Enum<E extends Enum<E>> extends Object implements Comparable<E>, Serializable
 *                  为什么 Enum 类需要使用如下这么奇怪的泛型，<E extends Enum<E>>，初次看真是让我晕了,
 *                  E 到底代表什么啊？为什么不定义成 public abstract class Enum extends Object 呢？
 *                  很容易找到答案，Enum 需要实现Comparable 比较接口。
 *                  那似乎也可以定义成 public abstract class Enum<E> extends Object implements Comparable<E>,
 *                  Serializable 。仔细想，就会发现会有问题，Comparable 的compareTo()方法是这样的：
 *                  public final int compareTo(E o)，我们肯定不希望这个 E 是任何类型的，而是希望这个E
 *                  是 Enum 类型的，同时我们不希望两个不同的 Enum 子类实例可以进行比较（没有意义），
 *                  即我们最希望的是同一个 Enum 子类的实例进行比较。
 * @author: cww
 * @DateTime: 2019-04-07 15:54
 */

public class BasicHolder<T> {
    T element;
    void set(T arg) {
        element = arg;
    }
    T get() {
        return element;
    }
    void f() {
        System.out.println(element.getClass().getSimpleName());
    }
}

class Subtype extends BasicHolder<Subtype> {}

class CRGWithBasicHolder {
    public static void main(String[] args) {
        Subtype st1 = new Subtype(),st2 = new Subtype();
        st1.set(st2);
        Subtype st3 = st1.get();
        st1.f();
    }
}

/**
 * *********************************************************
 */
class Other{}
class BasicOther extends BasicHolder<Other>{}

/**
 * 不受限定的类
 */
class Unconstrained {
    public static void main(String [] argv){
        BasicOther b = new BasicOther(), b2 = new BasicOther();
        b.set(new Other());
        Other other = b.get();
        b.f();
    }
}

/**
 * ******************************************************************
 * 自限定类型强制泛型当做其自己的边界参数来使用。
 *
 * 自限定所做的就是要求在继承关系中，强制要求将正在定义的类当做参数传递给基类。如果使用自限定，
 * 就应该了解这个类所用的类型参数与使用这个参数的类具有相同的基类型，这会要求使用这个类的每个人都要遵循这种形式；
 *
 * 自限定的参数意义：它可以保证类型参数必须与在被定义的类相同
 * @param <T>
 */
class SelfBounded<T extends SelfBounded<T>>{
    T element;
    SelfBounded<T> set(T arg){
        element=arg;
        return this;
    }
    T get(){return element;}
}

class A extends SelfBounded<A>{}
class B extends SelfBounded<A>{}
class C extends SelfBounded<C>{
    C setAndGet(C arg){
        set(arg);
        return get();
    }
}
class D{}

//因为类D没有继承SelfBounded，所以该类编译失败。
//class E extends SelfBounded<D>{}

class SelfBounding {
    public static void main(String[] args) {
        A a=new A();
        a.set(new A());
        a=a.set(new A()).get();
        a=a.get();
        C c=new C();
        c=c.setAndGet(new C());
    }
}

/**
 * 自限定用户与泛型方法
 * 这样的方法可以防止这个方法被应用于除下述形式的自限定参数之外的任何事物上
 */
class SelfBoundingMethods {
    static <T extends SelfBounded<T>> T f(T arg) {
        return arg.set(arg).get();
    }

    public static void main(String[] args) {
        A a = f(new A());
    }
}

